package com.zhaungjie.base.utils;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * LocalDateTime的运算函数
 *
 * @author zhuangjie
 * @date 2023/11/25
 */
public class LocalDateTimeOperations {
    private static final String DATE_SEPARATOR = "-";
    private static final String TIME_SEPARATOR = ":";
    private LocalDateTime localDateTime;

    /**
     * 将core Date 对象转为 LocalDateTime对象
     *
     * @return {@link LocalDateTime}
     */
    public LocalDateTime toLocalDateTime() {
        return this.localDateTime;
    }

    public LocalDateTimeOperations() {
        this.localDateTime = LocalDateTime.now();
    }

    public LocalDateTimeOperations(Date date) {
        setCore(date);
    }

    public LocalDateTimeOperations(LocalDateTime localDateTime) {
        setCore(localDateTime);
    }

    public LocalDateTimeOperations setCore(Date date) {
        this.localDateTime = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
        return this;
    }

    public LocalDateTimeOperations setCore(LocalDateTime localDateTime) {
        this.localDateTime = localDateTime;
        return this;
    }

    public LocalDateTimeOperations setYMD(Integer year, Integer month, Integer day) {
        this.localDateTime = this.localDateTime.withYear(year != null ? year : this.localDateTime.getYear());
        this.localDateTime = this.localDateTime.withMonth(month != null ? month : this.localDateTime.getMonthValue());
        this.localDateTime = this.localDateTime.withDayOfMonth(day != null ? day : this.localDateTime.getDayOfMonth());
        return this;
    }

    public long getTimeMillis() {
        return this.localDateTime.toInstant(ZoneOffset.UTC).toEpochMilli();
    }

    public LocalDateTimeOperations copyInstance() {
        return new LocalDateTimeOperations().setCore(Date.from(this.localDateTime.atZone(ZoneId.systemDefault()).toInstant()));
    }

    public LocalDateTimeOperations setHMS(Integer hour, Integer minute, Integer second) {
        this.localDateTime = this.localDateTime.withHour(hour != null ? hour : this.localDateTime.getHour());
        this.localDateTime = this.localDateTime.withMinute(minute != null ? minute : this.localDateTime.getMinute());
        this.localDateTime = this.localDateTime.withSecond(second != null ? second : this.localDateTime.getSecond());
        return this;
    }

    /**
     * 数组填充（通过分割得到有值的非等长数组填充到预定长度数组中）
     *
     * @param preSize        预先确定尺寸
     * @param initElementVal 初始化元素val
     * @param template       样板
     * @param separator      分离器
     * @return {@link List}<{@link Integer}>
     */
    private List<Integer> arrayFillForSplit(Integer preSize, Integer initElementVal, String template, String separator) {
        String[] arr = template.split(separator);
        List<Integer> result = new ArrayList<>(Collections.nCopies(preSize, initElementVal));
        for (Integer i = 0; i < preSize; i++) {
            Integer temp = initElementVal;
            try {
                temp = Integer.valueOf(arr[i]);
            } catch (ArrayIndexOutOfBoundsException e) {
            }
            result.set(i, temp);
        }
        return result;
    }

    /**
     * 更新core ，接收yyyy-MM-dd , HH:mm:dd 格式的数据进行更新
     *
     * @param ymd ymd
     * @param hms hms
     * @return {@link LocalDateTimeOperations}
     */
    public LocalDateTimeOperations update(String ymd, String hms) {
        if (ymd != null) {
            List<Integer> ymdArr = this.arrayFillForSplit(3, null, ymd, DATE_SEPARATOR);
            this.setYMD(ymdArr.get(0), ymdArr.get(1), ymdArr.get(2));
        }
        // 这里出错正常，直接忽略即可
        if (hms != null) {
            List<Integer> hmsArr = this.arrayFillForSplit(3, null, hms, TIME_SEPARATOR);
            this.setHMS(hmsArr.get(0), hmsArr.get(1), hmsArr.get(2));
        }
        return this;
    }

    public LocalDateTimeOperations addMinutes(int minutes) {
        this.localDateTime = this.localDateTime.plusMinutes(minutes);
        return this;
    }

    public LocalDateTimeOperations addDay(int dayNum) {
        this.localDateTime = this.localDateTime.plusDays(dayNum);
        return this;
    }

    public LocalDateTime getCore() {
        return this.localDateTime;
    }

    public Date getDateOfCore() {
        return Date.from(this.localDateTime.atZone(ZoneId.systemDefault()).toInstant());
    }

    public boolean hmsLt(String hms) {
        if (hms == null) throw new RuntimeException("无法对hms进行比较，因为传入的hms为空！");
        List<Integer> hmsArr = arrayFillForSplit(3, 0, hms, TIME_SEPARATOR);
        Integer hh = hmsArr.get(0), mm = hmsArr.get(1), ss = hmsArr.get(2);
        if (this.localDateTime.getHour() != hh) {
            return this.localDateTime.getHour() < hh;
        }
        if (this.localDateTime.getMinute() != mm) {
            return this.localDateTime.getMinute() < mm;
        }
        return this.localDateTime.getSecond() < ss;
    }

    public String formatDate(String formatString) {
        return this.localDateTime.format(DateTimeFormatter.ofPattern(formatString));
    }

    public String formatDate(DateTimeFormatter dateTimeFormatter) {
        return this.localDateTime.format(dateTimeFormatter);
    }

    public String getDayOfWeek() {
        String[] days = {"周日", "周一", "周二", "周三", "周四", "周五", "周六"};
        return days[this.localDateTime.getDayOfWeek().getValue() - 1];
    }

    /**
     * 获取年份
     *
     * @return 年份
     */
    public int getYear() {
        return this.localDateTime.getYear();
    }

    /**
     * 获取月份
     *
     * @return 月份
     */
    public int getMonth() {
        return this.localDateTime.getMonthValue();
    }

    /**
     * 获取日期
     *
     * @return 日期
     */
    public int getDay() {
        return this.localDateTime.getDayOfMonth();
    }

    /**
     * 获取小时
     *
     * @return 小时
     */
    public int getHour() {
        return this.localDateTime.getHour();
    }

    /**
     * 获取分钟
     *
     * @return 分钟
     */
    public int getMinute() {
        return this.localDateTime.getMinute();
    }

    /**
     * 获取秒钟
     *
     * @return 秒钟
     */
    public int getSecond() {
        return this.localDateTime.getSecond();
    }

}
